#pragma region Copyright
/// <copyright>
/// Copyright (c) 2007 Ilia Shramko.
/// Released under the terms of the GNU Lesser General Public License.
/// </copyright>
#pragma endregion

#include "stdafx.h"

#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <string.h>
#include <psapi.h>

#define BUFSIZE 512

bool Utils::GetFilePathFromHandle(HANDLE hFile, CString& filePath)
{
  bool bSuccess = false;
  TCHAR pszFilename[MAX_PATH+1];
  HANDLE hFileMap;

  // Get the file size.
  DWORD dwFileSizeHi = 0;
  DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi); 

  if(dwFileSizeLo == 0 && dwFileSizeHi == 0)
  {
	ATLTRACE_TS(atlTraceGeneral, TraceLevel::Verbose,
		"GetFileNameFromHandle() : Cannot map a file with a length of zero.\r\n");
     return false;
  }

  // Create a file mapping object.
  hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 1, NULL);
  if(hFileMap) 
  {
    // Create a file mapping to get the file name.
    void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
    if(pMem) 
    {
      if(GetMappedFileName(GetCurrentProcess(), pMem, pszFilename,MAX_PATH)) 
      {
        // Translate path with device name to drive letters.
        TCHAR szTemp[BUFSIZE];
        szTemp[0] = '\0';

        if(GetLogicalDriveStrings(BUFSIZE-1, szTemp)) 
        {
          TCHAR szName[MAX_PATH];
          TCHAR szDrive[3] = TEXT(" :");
          BOOL bFound = FALSE;
          TCHAR* p = szTemp;

          do 
          {
            // Copy the drive letter to the template string
            *szDrive = *p;

            // Look up each device name
            if(QueryDosDevice(szDrive, szName, BUFSIZE))
            {
              UINT uNameLen = (UINT)_tcslen(szName);

              if (uNameLen < MAX_PATH) 
              {
                bFound = _tcsnicmp(pszFilename, szName, 
                    uNameLen) == 0;

                if (bFound) 
                {
                  // Reconstruct pszFilename using szTemp
                  // Replace device path with DOS path
                  TCHAR szTempFile[MAX_PATH];
                  _stprintf_s(szTempFile, _countof(szTempFile), TEXT("%s%s"), szDrive, pszFilename+uNameLen);
                  _tcsncpy_s(pszFilename, _countof(szTempFile), szTempFile, MAX_PATH);
                }
              }
            }

            // Go to the next NULL character.
            while (*p++);
          } while (!bFound && *p); // end of string
        }
      }
      bSuccess = true;
      UnmapViewOfFile(pMem);
    } 

    CloseHandle(hFileMap);
  }

  filePath = pszFilename;

  return bSuccess;
}

HRESULT Utils::SaveBitmapFile(LPCWSTR pszFile, const BITMAPINFO* bitmapInfo)
{
	PBITMAPINFOHEADER pbih = (PBITMAPINFOHEADER) bitmapInfo;
	LPBYTE lpBits = (LPBYTE)((LPSTR)bitmapInfo + (WORD)(bitmapInfo->bmiHeader.biSize));

	BITMAPFILEHEADER hdr;       // bitmap file-header
	hdr.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M"
	// Compute the size of the entire file.
	hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + pbih->biSize + 
		pbih->biClrUsed * sizeof(RGBQUAD) + pbih->biSizeImage);
	hdr.bfReserved1 = 0;
	hdr.bfReserved2 = 0;

	// Compute the offset to the array of color indices. 
	hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + pbih->biSize + 
		pbih->biClrUsed * sizeof (RGBQUAD); 


	HRESULT hr = S_OK;

	// Create the .BMP file.
	HANDLE hf = ::CreateFile(pszFile, GENERIC_READ | GENERIC_WRITE, 0, NULL,
		CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if(hf == INVALID_HANDLE_VALUE)
		return AtlHresultFromLastError();

	// Copy the BITMAPFILEHEADER into the .BMP file. 
	DWORD dwTmp;
	if(::WriteFile(hf, &hdr, sizeof(BITMAPFILEHEADER), &dwTmp,  NULL))
	{
	    // Copy the BITMAPINFOHEADER and RGBQUAD array into the file. 
		if(::WriteFile(hf, pbih, sizeof(BITMAPINFOHEADER) + pbih->biClrUsed * sizeof (RGBQUAD),
			(LPDWORD) &dwTmp, NULL))
		{
			// Copy the array of color indices into the .BMP file. 
			DWORD cb = pbih->biSizeImage; 
			if(!::WriteFile(hf, lpBits, cb, &dwTmp, NULL))
				hr = AtlHresultFromLastError();
		}
		else
			hr = AtlHresultFromLastError();
	}
	else
		hr = AtlHresultFromLastError();


	// Close the .BMP file. 
	if(!CloseHandle(hf)) 
		hr = AtlHresultFromLastError();

	return hr;
}

